001 /*
002 * Copyright 2004-2005 Stephen J. McConnell.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
013 * implied.
014 *
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package net.dpml.metro.info;
020
021 import java.io.Serializable;
022 import java.beans.Introspector;
023 import java.lang.reflect.Method;
024
025
026 /**
027 * A descriptor that describes a value that must be placed
028 * in components Context. It contains information about;
029 * <ul>
030 * <li>key: the key that component uses to look up entry</li>
031 * <li>classname: the class/interface of the entry</li>
032 * <li>isOptional: true if entry is optional rather than required</li>
033 * </ul>
034 *
035 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
036 * @version 1.0.2
037 */
038 public final class EntryDescriptor implements Serializable, Comparable
039 {
040 /**
041 * Serial version identifier.
042 */
043 static final long serialVersionUID = 1L;
044
045 /**
046 * Constant prefix for get operations.
047 */
048 public static final String GET = "get";
049
050 /**
051 * Utility function that covers a supplied method to a
052 * entry name.
053 * @see Introspector#decapitalize(String)
054 * @param method the method
055 * @return the key
056 */
057 public static String getEntryKey( Method method )
058 {
059 String name = method.getName();
060 if( name.startsWith( GET ) )
061 {
062 String remainder = name.substring( GET.length() );
063 return Introspector.decapitalize( remainder );
064 }
065 else
066 {
067 final String error =
068 "Unrecognized context accessor method signature ["
069 + name
070 + "]";
071 throw new IllegalArgumentException( error );
072 }
073 }
074
075 /**
076 * Optional constant.
077 */
078 public static final boolean OPTIONAL = true;
079
080 /**
081 * Required constant.
082 */
083 public static final boolean REQUIRED = false;
084
085 /**
086 * The name the component uses to lookup entry.
087 */
088 private final String m_key;
089
090 /**
091 * The class/interface of the Entry.
092 */
093 private final String m_classname;
094
095 /**
096 * True if entry is optional, false otherwise.
097 */
098 private final boolean m_optional;
099
100 /**
101 * Immutable state of the entry.
102 */
103 private final boolean m_volatile;
104
105 /**
106 * Construct an non-volotile required EntryDescriptor.
107 * @param key the context entry key
108 * @param classname the classname of the context entry
109 * @exception NullPointerException if the key or type value are null
110 */
111 public EntryDescriptor( final String key, final String classname )
112 throws NullPointerException
113 {
114 this( key, classname, false );
115 }
116
117 /**
118 * Construct an non-volotile EntryDescriptor.
119 * @param key the context entry key
120 * @param classname the classname of the context entry
121 * @param optional TRUE if this is an optional entry
122 * @exception NullPointerException if the key or type value are null
123 */
124 public EntryDescriptor( final String key,
125 final String classname,
126 final boolean optional ) throws NullPointerException
127 {
128 this( key, classname, optional, false );
129 }
130
131 /**
132 * Construct an EntryDescriptor.
133 * @param key the context entry key
134 * @param classname the classname of the context entry
135 * @param optional TRUE if this is an optional entry
136 * @param isVolatile TRUE if the entry is consider to be immutable
137 * @exception NullPointerException if the key or type value are null
138 */
139 public EntryDescriptor( final String key,
140 final String classname,
141 final boolean optional,
142 final boolean isVolatile ) throws NullPointerException
143 {
144 if ( null == key )
145 {
146 throw new NullPointerException( "key" );
147 }
148 if ( null == classname )
149 {
150 throw new NullPointerException( "classname" );
151 }
152
153 m_key = key;
154 m_classname = classname;
155 m_optional = optional;
156 m_volatile = isVolatile;
157 }
158
159 /**
160 * Return the key that Component uses to lookup entry.
161 *
162 * @return the key that Component uses to lookup entry.
163 */
164 public String getKey()
165 {
166 return m_key;
167 }
168
169 /**
170 * Return the type of value that is stored in the context entry.
171 *
172 * @return the context entry classname
173 */
174 public String getClassname()
175 {
176 return m_classname;
177 }
178
179 /**
180 * Return true if entry is optional, false otherwise.
181 *
182 * @return true if entry is optional, false otherwise.
183 */
184 public boolean getOptional()
185 {
186 return m_optional;
187 }
188
189 /**
190 * Return true if entry is optional, false otherwise.
191 *
192 * @return true if entry is optional, false otherwise.
193 */
194 public boolean isOptional()
195 {
196 return getOptional();
197 }
198
199 /**
200 * Return true if entry is required, false otherwise.
201 *
202 * @return true if entry is required, false otherwise.
203 */
204 public boolean isRequired()
205 {
206 return !isOptional();
207 }
208
209 /**
210 * Return true if entry is volotile.
211 *
212 * @return the volatile state of the entry
213 */
214 public boolean isVolatile()
215 {
216 return getVolatile();
217 }
218
219 /**
220 * Return true if entry is volotile.
221 *
222 * @return the volatile state of the entry
223 */
224 public boolean getVolatile()
225 {
226 return m_volatile;
227 }
228
229 /**
230 * Test is the supplied object is equal to this object.
231 * @param other the object to compare with this instance
232 * @return true if the object are equivalent
233 */
234 public boolean equals( Object other )
235 {
236 if( other == null )
237 {
238 return false;
239 }
240
241 if( !( other instanceof EntryDescriptor ) )
242 {
243 return false;
244 }
245
246 EntryDescriptor entry = (EntryDescriptor) other;
247
248 if( m_optional != entry.m_optional )
249 {
250 return false;
251 }
252
253 if( m_volatile != entry.m_volatile )
254 {
255 return false;
256 }
257
258 if( !m_key.equals( entry.m_key ) )
259 {
260 return false;
261 }
262
263 if( !m_classname.equals( entry.m_classname ) )
264 {
265 return false;
266 }
267
268 return true;
269 }
270
271 /**
272 * Return the hashcode for the object.
273 * @return the hashcode value
274 */
275 public int hashCode()
276 {
277 int hash = m_key.hashCode();
278 hash ^= m_classname.hashCode();
279 if( m_volatile )
280 {
281 hash = hash + 1806621635;
282 }
283 else
284 {
285 hash = hash - 1236275651;
286 }
287 if( m_optional )
288 {
289 hash = hash + 1232368545;
290 }
291 else
292 {
293 hash = hash - 923798133;
294 }
295 return hash;
296 }
297
298 /**
299 * Compare this entry with another entry.
300 * @param other the other object
301 * @return the comparative index
302 */
303 public int compareTo( Object other )
304 {
305 if( null == other )
306 {
307 throw new NullPointerException( "other" );
308 }
309 EntryDescriptor entry = (EntryDescriptor) other;
310 if( getOptional() == entry.getOptional() )
311 {
312 return m_key.compareTo( entry.getKey() );
313 }
314 else if( isRequired() )
315 {
316 return -1;
317 }
318 else
319 {
320 return 1;
321 }
322 }
323 }